Option Explicit
'
'
'  Creator:    $Paul_M_Thompson@Yahoo.Com $
'  File:       C:\Users\Public\Documents\Virtual Machines\VmWareShare\Source\vbs\DTCC.vbs
'  Script:     bat.DTCC and DTCC.vbs
'  Revision:   $Revision: 224 $
'  Id:         $Id: DTCC.vbs 224 2014-11-06 16:13:07Z mnemotronic $
'
'
'
'
CONST vbForReading = 1              ' Open a file for reading only. You can't write to this file.
CONST vbForWriting = 2              ' Open a file for writing.
CONST vbForAppending = 8            ' Open a file and write to the end of the file.
CONST vbTristateUseDefault = -2     ' Opens the file using the system default.
CONST vbTristateTrue = -1           ' Opens the file as Unicode.
CONST vbTristateFalse = 0           ' Opens the file as ASCII.
'
'
CONST PATHDELIM = "\"
CONST WORKING_DIR       = "C:\Serena\ReleaseAutomationAgent\core\var\work\EIS_SQL"
CONST DEPLOY_DIR        = "C:\Serena\ReleaseAutomationAgent\core\var\work\tmp\deploy"
CONST MANIFEST_FNAME    = "C:\Serena\ReleaseAutomationAgent\core\var\work\EIS_SQL\manifest.txt"
CONST PROCESS_FNAME     = "C:\Serena\ReleaseAutomationAgent\core\var\work\tmp\process.txt"
'
' New requirement 14-Oct-2014.
CONST PREDEPLOY_FNAME   = "C:\Serena\ReleaseAutomationAgent\core\var\work\tmp\predeploy_loop.txt"
CONST POSTDEPLOY_FNAME  = "C:\Serena\ReleaseAutomationAgent\core\var\work\tmp\postdeploy_loop.txt"
'
CONST DEBUG_FLAG = True
CONST MANIFEST_FILELIST_DELIMITER = ";"
CONST SEQUENCE_FIELD_WIDTH = 8
'
' ----------------------------------------------------------------------------
'
Dim obj_Args , dict_Manifest , txtstream_ManifestFile , txtstream_ProcessFile , fso
Dim regex_ManifestLine , match_ManifestLine
Dim ary_SequencedManifest()
Dim   i , rslt , strArg , str_Delimited_Manifest_Filelist , n_MaxSeqId , nSeq , _
      str_Line , str_ManifestEntryFilename , str_ManifextEntrySequenceId , _
      n_ManifestMods , manifest_entries , b_PrePost_Files
'
' ----------------------------------------------------------------------------
'
'  Iterate all command line args.
'     Normally there will be none - everything is hardcoded.
'     cscript DTCC.vbs UnNamed_Arg_1 /Named_Arg1:"Named Arg 1 value"
Set obj_Args = WScript.Arguments.Unnamed
For i = 0 To obj_Args.Count - 1
   WScript.Echo "DEBUG :: UnNamed Command Line Arg(" & i & "):" & obj_Args(i)
Next
'
Set obj_Args = WScript.Arguments.Named
For Each strArg in obj_Args
   WScript.Echo "DEBUG :: Named Command Line Arg[" & strArg & "]:" & obj_Args.Item(strArg)
Next
'
'
' Startup tests and diagnostics
If Not FolderExists(WORKING_DIR) Then
   WScript.Echo "Can't find Working dir: " & WORKING_DIR & "'.  Now what do we do?!?!?!"
Else
   WScript.Echo "FOUND Working dir: " & WORKING_DIR & "'"
End If
'
If Not FolderExists(DEPLOY_DIR) Then
   WScript.Echo "Can't find Deploy dir: " & DEPLOY_DIR & "'.  Now what do we do?!?!?!"
Else
   WScript.Echo "FOUND Deploy dir: " & DEPLOY_DIR & "'"
End If
'
If Not FileExists(MANIFEST_FNAME) Then
   WScript.Echo "Can't find MANIFEST file: " & MANIFEST_FNAME & "'.  I guess that's bad news.  Now what?!?!?"
Else
   WScript.Echo "FOUND MANIFEST file: " & MANIFEST_FNAME & "'"
End If
'
If Not FileExists(PROCESS_FNAME) Then
   WScript.Echo "Can't find PROCESS.TXT file: " & PROCESS_FNAME & "'.  I guess that's bad news.  Now what?!?!?"
Else
   WScript.Echo "FOUND PROCESS.TXT file: " & PROCESS_FNAME & "'"
End If
'
' New requirement 14-Oct-2014:  If Oracle, prepend and append special files
'  to the artifact file.  We know it's Oracle if the "prepend" and "append"
'  files exist.
' Bail out with error if only one of the files exists.
If (FileExists(PREDEPLOY_FNAME) AND NOT FileExists(POSTDEPLOY_FNAME)) OR (NOT FileExists(PREDEPLOY_FNAME) AND FileExists(POSTDEPLOY_FNAME)) Then
   WScript.Echo "ERROR: Only one of the Pre / Post deploy files exists.  Exiting with error code."
   WScript.Quit 1
Else
End If
'
' If both files exist, we call it an Oracle deploy and set a flag that will
'     tell us to prepend the PREDEPLOY file to the artifact and append the
'     POSTDEPLOY file.
If FileExists(PREDEPLOY_FNAME) AND FileExists(POSTDEPLOY_FNAME) Then
   b_PrePost_Files = True
   If DEBUG_FLAG Then WScript.echo "DEBUG :: Oracle deploy -- Add Pre & Post-Deploy scripts to artifact."
else
   b_PrePost_Files = False
   If DEBUG_FLAG Then WScript.echo "DEBUG :: Pre & Post-Deploy scripts not found."
End If
'
'
'
'
'  Every filename we find in the Manifest, delimited by by the
'     MANIFEST_FILELIST_DELIMITER character.
'  When the scanning process.txt file, check "is filename from process.txt in
'     the delimited manifest filelist string"?  An "INSTR()" is much faster
'     than iterating the manifest for each line read from process.txt file,
'     especially because process.txt will grow forever.
'
' Delete all files from the Deploy dir
If DEBUG_FLAG Then WScript.Echo "DEBUG :: Deleting all files and subdirs in the Deploy dir '" & DEPLOY_DIR & "'"
Call DeleteFiles(DEPLOY_DIR & PATHDELIM & "*")
Call DeleteFolders(DEPLOY_DIR & PATHDELIM & "*")
'
' - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- -
'  Read the manifest file and build dictionary, one entry per line.
'     Keys are filenames, values are sequence number.
'
Set fso = CreateObject("Scripting.FileSystemObject")
Set dict_Manifest = CreateObject("Scripting.Dictionary")
'
' Regular expression to process a line from the manifest file:
'     Skip any WHITESPACE chars
'     Capture 0 or more digits
'     Skip any WHITESPACE chars
'     Capture 0 or more non-WHITESPACE chars
Set regex_ManifestLine = GetRegEx("^\s*(\d+)\s+(\S+)",true,false)
'
WScript.Echo "Reading Manifest file '" & MANIFEST_FNAME & "'"
Set txtstream_ManifestFile = fso.OpenTextFile(MANIFEST_FNAME, vbForReading, false, vbTristateUseDefault)
'
'
While Not txtstream_ManifestFile.AtEndOfStream
   str_Line = txtstream_ManifestFile.ReadLine
   WScript.echo "DEBUG :: Manifest line='" & str_Line & "'"
   Set match_ManifestLine = regex_ManifestLine.Execute(str_Line)
   If match_ManifestLine.Count > 0 Then
      str_ManifextEntrySequenceId = Trim(match_ManifestLine(0).SubMatches(0))
      str_ManifestEntryFilename = Trim(match_ManifestLine(0).SubMatches(1))
      WScript.Echo "DEBUG :: Seq#=" & str_ManifextEntrySequenceId & " ; file=" & str_ManifestEntryFilename
      ' Save highest Sequence ID
      nSeq = CLng(str_ManifextEntrySequenceId)
      If nSeq > n_MaxSeqId Then n_MaxSeqId = nSeq
      ' Add this filename to the dictionary
      Call dict_Manifest.Add( str_ManifestEntryFilename , str_ManifextEntrySequenceId )
      ' append filename to the delimited list.
      str_Delimited_Manifest_Filelist = str_Delimited_Manifest_Filelist & MANIFEST_FILELIST_DELIMITER & str_ManifestEntryFilename
   Else
      ' Blank line
   End If
Wend
'
' Dont need this stuff anymore.
txtstream_ManifestFile.Close
set txtstream_ManifestFile = Nothing
Set match_ManifestLine = Nothing
Set regex_ManifestLine = Nothing
'
'
' Append a trailing delimiter to the delimited list.
str_Delimited_Manifest_Filelist = str_Delimited_Manifest_Filelist & MANIFEST_FILELIST_DELIMITER
'
'
If DEBUG_FLAG Then wscript.echo "DEBUG :: Delimited Manifest Filelist = '" & str_Delimited_Manifest_Filelist & "'"
If DEBUG_FLAG Then wscript.echo "DEBUG :: max sequence id=" & n_MaxSeqId
'
' - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- -
'
'Now read the process.txt file and look for any entries matching what we've
'     read from the manifest.  If file from process.txt is in the manifest
'     list then that file has been deployed.  Remove that file from the
'     in-memory manifest.  Keep track of number of changes made to the
'     manifest.
'
WScript.Echo "Reading process file '" & PROCESS_FNAME & "'"
Set txtstream_ProcessFile = fso.OpenTextFile(PROCESS_FNAME, vbForReading, false, vbTristateUseDefault)
'
While Not txtstream_ProcessFile.AtEndOfStream
   str_Line = Trim(txtstream_ProcessFile.ReadLine)
   If DEBUG_FLAG Then wscript.echo "DEBUG:: Process file line '" & str_Line & "'"
   If Instr(1,str_Delimited_Manifest_Filelist, MANIFEST_FILELIST_DELIMITER & str_Line & MANIFEST_FILELIST_DELIMITER, vbTextCompare) > 0 Then
      wscript.echo "DEBUG :: Found Manifest file '" & str_Line & "' in PROCESS.TXT"
      dict_Manifest.Remove(str_Line)
      n_ManifestMods = n_ManifestMods + 1
   Else
   End If
'
Wend
'
txtstream_ProcessFile.Close
Set txtstream_ProcessFile = Nothing
'
wscript.echo CStr(n_ManifestMods) & " manifest entries modified"
'
' - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- -
'
' Copy the remaining in-memory Manifest filenames to an array.  This gets
'     them into order by sequence number.  We'll need this when we write
'     the remaining manifest entries back to the manifest file.
' wscript.echo "Before REDIM SequencedManifest array lBound=" & LBound(ary_SequencedManifest) & " uBound=" & UBound(ary_SequencedManifest)
ReDim ary_SequencedManifest(n_MaxSeqId)
If DEBUG_FLAG Then wscript.echo "DEBUG :: After REDIM SequencedManifest array lBound=" & LBound(ary_SequencedManifest) & " uBound=" & UBound(ary_SequencedManifest)
'
For Each str_Line in dict_Manifest
   If DEBUG_FLAG Then wscript.echo "create sequenced manifest list : index = " & CLng(dict_Manifest.Item(str_Line)) & " value = " & str_Line
   ary_SequencedManifest( CLng(dict_Manifest.Item(str_Line)) ) = str_Line
Next
'
If DEBUG_FLAG Then
   For i=0 to UBound(ary_SequencedManifest)
      wscript.echo "DEBUG :: ary_SequencedManifest manifest(" & i & ") == " & ary_SequencedManifest(i)
   Next
End IF
'
' - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- -
'
' If the in-memory manifest dictionary was modified save it back to the
'     manifest file.  This needs to be done in sequence order.
'
If n_ManifestMods > 0 Then
'
   ' Save updated in-memory manifest back to file.  Entries must be in sequence
   '     order.  While doing this keep track of number of valid lines we write
   '     to the manifest file.  If it's none, then the manifest list is empty
   '     which means everything has been deployed which means this deploy
   '     cycle is complete
   ' Delete the manifest file as a signal to RLM.
'
   Set txtstream_ProcessFile = fso.OpenTextFile(MANIFEST_FNAME, vbForWriting, false, vbTristateUseDefault)
'
   manifest_entries = 0
   For i=0 to UBound(ary_SequencedManifest)
      If Len(ary_SequencedManifest(i)) > 0 Then
         If DEBUG_FLAG Then wscript.echo "DEBUG :: ary_SequencedManifest manifest(" & i & ") == " & ary_SequencedManifest(i)
         manifest_entries = manifest_entries + 1
         Call txtstream_ProcessFile.WriteLine( LPad(i,"0",SEQUENCE_FIELD_WIDTH) & "   " & ary_SequencedManifest(i) )
      End If
   Next
'
'
   If manifest_entries < 1 Then
      WScript.Echo "Manifest has no more files.  Deleting empty manifest file."
      Call DeleteFiles(MANIFEST_FNAME)
      Call WScript.Quit(0)
   End If
'
Else
   WScript.Echo "Manifest not modified."
End If
'
' - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- - -- -
'
' For each line in manifest, if file exists in working dir then copy to
'  deploy dir and quit script immediately.
' If file doesn't exist in the working dir, then the working dir is out
'  of sync with the manifest list.  Exit immediately with error status.
'
      wscript.echo "If file from manifest list exists in working dir then copy to the deploy dir and exit post haste."
For i=0 to UBound(ary_SequencedManifest)
   If Len(ary_SequencedManifest(i)) > 0 Then
      wscript.echo "File '" & WORKING_DIR & PATHDELIM & ary_SequencedManifest(i) & "' exists."
      If FileExists(WORKING_DIR & PATHDELIM & ary_SequencedManifest(i)) Then
         ' copy file
         WScript.Echo "CopyFile(" & WORKING_DIR & PATHDELIM & ary_SequencedManifest(i) & _
            "," & DEPLOY_DIR & PATHDELIM & ary_SequencedManifest(i) & ")"
'
         If b_PrePost_Files Then
            rslt = CopyFileWithPrePost( _
               PREDEPLOY_FNAME , _
               WORKING_DIR & PATHDELIM & ary_SequencedManifest(i) , _
               POSTDEPLOY_FNAME , _
               DEPLOY_DIR & PATHDELIM & ary_SequencedManifest(i) _
            )
         Else
            rslt = fso.CopyFile(WORKING_DIR & PATHDELIM & ary_SequencedManifest(i),DEPLOY_DIR & PATHDELIM & ary_SequencedManifest(i),True)
            WScript.Echo "CopyFile result = " & rslt
         End If
'
         WScript.Echo "Now go deploy that file!"
         Call WScript.Quit(0)
'
      Else
         wscript.echo "File '" & ary_SequencedManifest(i) & "' does not exist" & _
            " in the working dir.  This means the working dir is out-of-sync" & _
            " with the files listed in the manifest file." & vbCrLf & _
            "Bail out with extreme prejudice."
         Call WScript.Quit(-2)
      End If
'
'
   End If
Next
'
'
' ----------------------------------------------------------------------------
' ----------------------------------------------------------------------------
Function FileExists(strFname)
   Dim fso
   Set fso = CreateObject("Scripting.FileSystemObject")
   FileExists = fso.FileExists(strFname)
   Set fso = Nothing
End Function
' ----------------------------------------------------------------------------
Function FolderExists(strDirname)
   Dim fso
   Set fso = CreateObject("Scripting.FileSystemObject")
   FolderExists = fso.FolderExists(strDirname)
   Set fso = Nothing
End Function
' ----------------------------------------------------------------------------
'  Delete specified file(s).  USE WITH CAUTION
Function DeleteFiles(str_Path)
   Dim fso
   Set fso = CreateObject("Scripting.FileSystemObject")
   wscript.echo "DEBUG :: Delete files: " & str_Path
   rslt = fso.DeleteFile(str_Path, True)
   WScript.Echo "DeleteFile result = " & rslt
'
   Set fso = Nothing
End Function
' ----------------------------------------------------------------------------
'  Delete everything in the specified dir.  USE WITH CAUTION
Function DeleteFolders(str_Path)
   Dim fso
   Set fso = CreateObject("Scripting.FileSystemObject")
   wscript.echo "DEBUG :: Delete folders: " & str_Path
   rslt = fso.DeleteFolder(str_Path, True)
   WScript.Echo "DeleteFolder result = " & rslt
   Set fso = Nothing
End Function
' ----------------------------------------------------------------------------
' Create & return a Regular Expression object given the pattern and flags.
'  Within the body of a VBScript function we can treat the function name
'     as a declared variable.
Function GetRegEx(str_Pattern , bool_IgnoreCase , bool_Global)
   Set GetRegEx = New RegExp
'
   GetRegEx.Pattern = str_Pattern
   GetRegEx.IgnoreCase = bool_IgnoreCase
   GetRegEx.Global = bool_Global
End Function
'
' ----------------------------------------------------------------------------
'  Left-pad the first param with the second param and return a string the
'     length of the third param.
Function LPad(i,str,nWidth)
   Dim tmpstr
   tmpstr = CStr(i)
   LPad = Left(String(str,nWidth),nWidth-Len(tmpstr)) & tmpstr
End Function
'
' ----------------------------------------------------------------------------
' Copy the Pre, Artifact and Post file contents to the Destination file.
'  Append CR/LF to lines lacking those.
Function CopyFileWithPrePost( str_PreFname , str_ArtifactFname , str_PostFname , str_DestFname)
'
WScript.Echo "SPECIAL DEBUG :: PREDEPLOY filename='" & str_PreFname & "'"
WScript.Echo "SPECIAL DEBUG :: Artifact filename='" & str_ArtifactFname & "'"
WScript.Echo "SPECIAL DEBUG :: POSTDEPLOY filename='" & str_PostFname & "'"
WScript.Echo "SPECIAL DEBUG :: Destination filename='" & str_DestFname & "'"
'
   Dim fso , txtstream_In , txtstream_Out
   Set fso = CreateObject("Scripting.FileSystemObject")
   Set txtstream_Out = fso.OpenTextFile(str_DestFname, vbForWriting, True)
'
   'Read the Predeploy file and write it to the destination
WScript.Echo "DEBUG :: copy PreDeploy contents to: '" & str_DestFname & "'"
   Set txtstream_In = fso.OpenTextFile(str_PreFname, vbForReading)
   Call txtstream_Out.Write( txtstream_In.ReadAll & vbNewLine)
   Call txtstream_In.Close
   Set txtstream_In = Nothing
'
WScript.Echo "DEBUG :: copy artifact contents to: '" & str_DestFname & "'"
   Set txtstream_In = fso.OpenTextFile(str_ArtifactFname, vbForReading)
   Call txtstream_Out.Write( txtstream_In.ReadAll & vbNewLine)
   Call txtstream_In.Close
   Set txtstream_In = Nothing
'
WScript.Echo "DEBUG :: copy PostDeploy contents to: '" & str_DestFname & "'"
   Set txtstream_In = fso.OpenTextFile(str_PostFname, vbForReading)
   Call txtstream_Out.Write( txtstream_In.ReadAll & vbNewLine)
   ' Cleanup and quit
   Call txtstream_In.Close
   Call txtstream_Out.Close
   Set txtstream_In = Nothing
   Set txtstream_Out = Nothing
   Set fso = Nothing
'
   CopyFileWithPrePost = True
'
End Function
